package com.zimi.service;

import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zimi.bean.SmsInfo;
import com.zimi.mapper.SysUserMapper;
import com.zimi.model.SysRoleUser;
import com.zimi.model.SysUser;
import com.zimi.util.MD5Util;
import com.zimi.util.ShiroUtils;
import org.apache.shiro.session.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class RegistryService {
    @Value("${smsurl.url:http://www.qybor.com:8500/shortMessage}")
    private String smsPath;

    @Value("${smsurl.name:ynzimi}")
    private String name;

    @Value("${smsurl.passwd:ynzimi26}")
    private String passwd;

    @Value("${smsurl.port:000}")
    private String port;

    @Value("${smsurl.needstatus:true}")
    private String needstatus;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Transactional
    public void registry(SysUser sysUser) {
        // 1)取出手机号
        Session session = ShiroUtils.getSession();
        Object obj = session.getAttribute("phone");

        SysUser tmpUser = null;

        if (obj == null) {
            throw new RuntimeException("确认验证码失败，请重新取得验证码。");
        }

        tmpUser = sysUserMapper.selectOne(new QueryWrapper<SysUser>().lambda().eq(SysUser::getLoginName, sysUser.getLoginName()));

        if (tmpUser != null) {
            throw new RuntimeException("该登录名已注册过，请修改登录名再注册。");
        }

        tmpUser = sysUserMapper.selectOne(new QueryWrapper<SysUser>().lambda().eq(SysUser::getUserPhone, (String) obj));

        // 2)判断该手机已经注册了没有
        if (tmpUser == null) {
            Date now = new Date();
            sysUser.setLoginName((String) obj);
            sysUser.setUserLoginpwd(MD5Util.encode(sysUser.getUserLoginpwd()));
            sysUser.setFileId(0);
            sysUser.setUserPhone((String) obj);
            sysUser.setCreateUser(0);
            sysUser.setCreateTime(now);

            sysUser.insert();

            // 3)成为新会员后带流程（最基础）的权限
            SysRoleUser sysRoleUser = new SysRoleUser();
            sysRoleUser.setUserId(sysUser.getId());
            sysRoleUser.setRoleId(2);
            sysRoleUser.setState(1);
            sysRoleUser.setCreateUser(sysUser.getId());
            sysRoleUser.setCreateTime(now);

            sysRoleUser.insert();

        } else {
            throw new RuntimeException("该手机号已注册过，请找回密码并登录。");
        }
    }

    @Transactional
    public void verify(String verifyCode) {
        // 1)取出验证码
        Session session = ShiroUtils.getSession();
        Object obj = session.getAttribute("veryNum");

        if (obj == null) {
            throw new RuntimeException("确认验证码失败，请重新取得验证码。");
        } else {
            if (!((Integer) obj).toString().equals(verifyCode)) {
                throw new RuntimeException("确认验证码失败，请重新取得验证码。");
            }

            obj = session.getAttribute("veryTime");
            if (obj == null) {
                throw new RuntimeException("确认验证码失败，请重新取得验证码。");
            } else {
                Date veryTime = (Date) obj;
                Date now = new Date();

                int diffTime = (int) (now.getTime() - veryTime.getTime());

                if (diffTime > 15 * 60 * 1000) {
                    session.removeAttribute("veryTime");
                    session.removeAttribute("veryNum");
                    throw new RuntimeException("验证码超过15分钟有效时间，请重新取得验证码。");
                }

                // 确认手机号是否已注册过
                obj = session.getAttribute("phone");

                if (obj == null) {
                    throw new RuntimeException("确认验证码失败，请重新取得验证码。");
                }

                SysUser tmpUser = sysUserMapper.selectOne(new QueryWrapper<SysUser>().lambda().eq(SysUser::getUserPhone, (String) obj));

                if (tmpUser != null) {
                    throw new RuntimeException("该手机号已注册过，请找回密码并登录。");
                }
            }
        }

        session.removeAttribute("veryNum");
        session.setAttribute("phoneCheck", 0);
    }

    @Transactional
    public void forPasswordVerify(String verifyCode) {
        // 1)取出验证码
        Session session = ShiroUtils.getSession();
        Object obj = session.getAttribute("veryNum2");

        if (obj == null) {
            throw new RuntimeException("确认验证码失败，请重新取得验证码。");
        } else {
            if (!((Integer) obj).toString().equals(verifyCode)) {
                throw new RuntimeException("确认验证码失败，请重新取得验证码。");
            }

            obj = session.getAttribute("veryTime2");
            if (obj == null) {
                throw new RuntimeException("确认验证码失败，请重新取得验证码。");
            } else {
                Date veryTime = (Date) obj;
                Date now = new Date();

                int diffTime = (int) (now.getTime() - veryTime.getTime());

                if (diffTime > 15 * 60 * 1000) {
                    session.removeAttribute("veryTime2");
                    session.removeAttribute("veryNum2");
                    throw new RuntimeException("验证码超过15分钟有效时间，请重新取得验证码。");
                }

                // 确认手机号是否已注册过
                obj = session.getAttribute("phone2");

                if (obj == null) {
                    throw new RuntimeException("确认验证码失败，请重新取得验证码。");
                }

                SysUser tmpUser = sysUserMapper.selectOne(new QueryWrapper<SysUser>().lambda().eq(SysUser::getUserPhone, (String) obj));

                if (tmpUser == null) {
                    throw new RuntimeException("该手机号没有注册过，请注册后使用。");
                }

                String passWord = getCharAndNumr(8);
                tmpUser.setUserLoginpwd(MD5Util.encode(passWord));
                tmpUser.setUpdateUser(tmpUser.getId());
                tmpUser.setUpdateTime(now);
                tmpUser.setUserState(1);
                tmpUser.updateById();

                SmsInfo smsInfo = new SmsInfo();
                smsInfo.setMobile((String) obj);
                System.out.println(passWord);
                smsInfo.setContent(String.format("【云南紫米】系统为您重置了密码。\r\n账号：%s\r\n新的密码：%s\r\n为保证信息安全，切勿将账号和密码告知他人。", tmpUser.getLoginName(), passWord));
                try {
                    this.postSMS(smsInfo);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        session.removeAttribute("veryNum2");
        session.removeAttribute("phone2");
        session.removeAttribute("veryTime2");
    }

    @Transactional
    public void sendVerification(String phone) {
        // 1）验证手机号
        if (phone == null || phone.length() != 11) {
            throw new RuntimeException("请输入正确格式的手机号。");
        } else {
            // 2)验证手机号码格式
            String regex = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$";
            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(phone);

            if (!m.matches()) {
                throw new RuntimeException("请输入正确格式的手机号。");
            }

            //3)发送验证码
            Date currentTime = new Date();
            currentTime.setTime(currentTime.getTime() + 3 * 60 * 1000);
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

            try {
                SmsInfo smsInfo = new SmsInfo();
                smsInfo.setMobile(phone);
                int veryNum = (int) ((Math.random() * 9 + 1) * 100000);
                System.out.println(veryNum);
                smsInfo.setContent(String.format("【云南紫米】注册验证码是：\r\n%d,用于注册紫米ERP，请尽快提交您的验证码。为保证信息安全，切勿将验证码告知他人。", veryNum));
                smsInfo.setSendTime(df.format(currentTime));
                this.postSMS(smsInfo);

                // 4)保存手机号
                Session session = ShiroUtils.getSession();
                session.setAttribute("phone", phone);
                session.setAttribute("veryNum", veryNum);
                session.setAttribute("veryTime", new Date());
            } catch (IOException e) {
                throw new RuntimeException("发送短信失败！");
            }
        }
    }

    @Transactional
    public void forPasswordSendVerification(String phone) {
        // 1）验证手机号
        if (phone == null || phone.length() != 11) {
            throw new RuntimeException("请输入正确格式的手机号。");
        } else {
            // 2)验证手机号码格式
            String regex = "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$";
            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(phone);

            if (!m.matches()) {
                throw new RuntimeException("请输入正确格式的手机号。");
            }

            // 3)查询手机号用户
            SysUser sysUser = sysUserMapper.selectOne(new QueryWrapper<SysUser>().lambda().eq(SysUser::getUserPhone, phone));

            if (sysUser == null) {
                throw new RuntimeException("该手机号没有注册过，请注册后使用。");
            }

            // 4)发送验证码
            Date currentTime = new Date();
            currentTime.setTime(currentTime.getTime() + 3 * 60 * 1000);
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

            try {
                SmsInfo smsInfo = new SmsInfo();
                smsInfo.setMobile(phone);
                int veryNum = (int) ((Math.random() * 9 + 1) * 100000);
                System.out.println(veryNum);
                smsInfo.setContent(String.format("【云南紫米】重置账号密码验证码是：\r\n%d,用于重置紫米ERP账号密码，请尽快提交您的验证码。为保证信息安全，切勿将验证码告知他人。", veryNum));
                smsInfo.setSendTime(df.format(currentTime));
                this.postSMS(smsInfo);

                // 5)保存手机号
                Session session = ShiroUtils.getSession();
                session.setAttribute("phone2", phone);
                session.setAttribute("veryNum2", veryNum);
                session.setAttribute("veryTime2", new Date());
            } catch (IOException e) {
                throw new RuntimeException("发送短信失败！");
            }
        }
    }

    /*
     * @length 密码长度8
     * */
    private String getCharAndNumr(int length) {
        String val = "";
        Random random = new Random();
        for (int i = 0; i < length; i++) {
            // 输出字母还是数字
            String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
            // 字符串
            if ("char".equalsIgnoreCase(charOrNum)) {
                // 取得大写字母还是小写字母
                int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
                val += (char) (choice + random.nextInt(26));
            } else if ("num".equalsIgnoreCase(charOrNum)) { // 数字
                val += String.valueOf(random.nextInt(10));
            }
        }
        return val;
    }

    /**
     * @param smsInfo
     * @throws IOException
     */
    private void postSMS(SmsInfo smsInfo) throws IOException {
        HashMap<String, Object> paramMap = new HashMap<>();
        paramMap.put("username", name);
        paramMap.put("passwd", passwd);
        paramMap.put("port", port);
        paramMap.put("needstatus", needstatus);
        paramMap.put("phone", smsInfo.getMobile());
        paramMap.put("msg", smsInfo.getContent());
        paramMap.put("SendTime", smsInfo.getSendTime());

        String result = HttpUtil.post(smsPath, paramMap);

        System.out.println(result);
    }
}
